O curso está dividido em três blocos: uma parte teórica, a parte prática da análise exploratória e uma incursão inicial em direção à Estatística inferencial (ou seja, como podemos generalizar as observações da amostra para a população). Vamos ficar por mais tempo no segundo bloco.
Ao longo do curso abordaremos dois aspectos da Estatística para Ciências Sociais: a Estatística descritiva e a inferencial. A análise exploratória lida principalmente com a primeira, mas ela usualmente opera como etapa preparatória para a segunda.
A pesquisa empírica em Ciências Sociais muitas vezes é limitada pela disponibilidade de dados. Portanto, ter acesso a toda a população de interesse em determinada pesquisa é frequentemente inviável. É justamente essa a definição de “universo”: o conjunto que contém todos os elementos com as características em análise. No caso do nosso exemplo, o universo seria toda a população jovem. Mais precisamente, a população entre 15 a 29 anos.
Uma pesquisa que se aproxima da coleta de dados de todo o universo de interesse sãos os Censos Demográficos. Mas justamente pelos custos e pela dificuldade de realização da pesquisa é que eles são conduzidos uma vez a cada década.
Portanto, a alternativa viável é coletar informações de parcelas do universo. Ou seja, obter amostras e a partir delas produzir inferências sobre o todo.
Contudo, nem todo método de obtenção de amostra é igual, e isso deve ser ponderado no momento de descrição e análise dos dados. A depender das condições de coleta e do tamanho da amostra, os dados podem ser invalidados e podem não ser passíveis de análise por meio de algumas técnicas estatísticas. Dito de outra forma, algumas amostras podem não ser generalizáveis para a população que queremos estudar. (Ter uma amostra com menos de 30 indivíduos é um exemplo.)
Vamos dar uma olhada em como a amostra do banco que vamos analisar foi construída:
Amostra OIT
Método “A pesquisa é estatisticamente representativa do universo da população nesta faixa etária, valendo-se de uma amostra composta por 3.288 entrevistas, distribuídas em 160 municípios, estratificados por localização geográfica (capital e interior, áreas urbanas e rurais) e em tercis de porte (municípios pequenos, médios e grandes) e contemplando 25 Unidades da Federação. A amostragem foi feita de forma probabilística nos primeiros estágios (sorteio dos municípios, dos setores censitários, dos quarteirões e dos domicílios), combinada com controle de cotas de sexo, idade e por condição do ponto (urbano ou rural) para a seleção dos indivíduos (estágio final). As margens de erro, se pudessem ser estimadas a partir de amostra puramente probabilística equivalente, seriam de até 2 pontos percentuais, para mais ou para menos, para o total da amostra, com intervalo de confiança de 95 por cento. Os critérios de dispersão, seleção e tamanho da amostra de jovens entrevistados/as garantem a representatividade dos resultados obtidos – guardados os parâmetros estatísticos do desenho amostral – para o conjunto do universo em foco: 51,3 milhões de jovens, correspondentes a 26,1 por cento do total da população brasileira (Censo 2010 – IBGE). Nas tabelas a seguir, os percentuais encontrados na pesquisa TET são projetados para os números absolutos desse universo juvenil. Foi feita a aplicação de questionários estruturados, em entrevistas pessoais e domiciliares (tempo médio de 40 minutos de aplicação). Total de 147 perguntas, parcialmente distribuídas em 6 blocos.” Fonte
Pesquisa Nacional por Amostra de Domicílios Contínua
PnadC
WVS
Por enquanto é isso: prestar atenção no desenho amostral na documentação das pesquisas que serão utilizadas. Vamos falar brevemente sobre a dimensão inferencial no tópico 3 do curso.
Em bancos de dados estruturados, as variáveis podem ser qualitativas ou quantitativas. O tipo de variável indica as possibilidades de descrição e visualização dos dados, tanto para análises univariadas quanto para as que levam em consideração cruzamentos e interações.
Quadro 1 - Fonte: Cervi (2017).
Quadro 2 - Fonte: Cervi (2017).
Quadro 3 - Fonte: Cervi (2017).
A análise descritiva ou exploratória dos dados é etapa fundamental da pesquisa. A partir dela podemos: a) determinar a qualidade dos dados coletados, b) mapear de maneira ordenada os atributos do conjunto de dados, c) estabelecer conexões entre variáveis, d) preparar os dados para análises estatísticas diversas, como produzir generalizações da amostra para o universo da população em análise.
Antes de abrir o banco, vamos retomar o dicionário de dados. É importante estar com a documentação do banco ao alcance durante toda a etapa inicial de preparo dos dados.
Codebook
Não é incomum termos que lidar com dados faltantes, erros de registro, valores discrepantes, linhas duplicadas e demais possíveis inconsistências nos dados. Nesse processo podemos fazer uso de recodificação e transformação das variáveis.
Vamos ao código!
library(tidyverse)
getwd()
## [1] "/cloud/project"
banco <-read.csv("/cloud/project/minicurso_r_sd.csv", sep = ";", dec = ",")
summary(banco)
## regiao sexo idade_quinquenal raca_cor
## Min. :1.000 Min. :1.000 Min. :1.000 Min. : 1.000
## 1st Qu.:3.000 1st Qu.:1.000 1st Qu.:1.000 1st Qu.: 1.000
## Median :4.000 Median :2.000 Median :2.000 Median : 3.000
## Mean :3.688 Mean :1.502 Mean :1.922 Mean : 9.646
## 3rd Qu.:5.000 3rd Qu.:2.000 3rd Qu.:3.000 3rd Qu.: 3.000
## Max. :5.000 Max. :2.000 Max. :3.000 Max. :997.000
##
## educ_mae ocup_mae educ_pai ocup_pai
## Min. : 1.000 Min. :1111 Min. : 1.00 Min. : 110
## 1st Qu.: 1.000 1st Qu.:5249 1st Qu.: 1.00 1st Qu.:5414
## Median : 1.000 Median :9121 Median : 2.00 Median :7411
## Mean : 6.908 Mean :7951 Mean :18.62 Mean :7209
## 3rd Qu.: 2.000 3rd Qu.:9994 3rd Qu.: 9.00 3rd Qu.:9211
## Max. :99.000 Max. :9998 Max. :99.00 Max. :9998
##
## educ pessoas classesocial rendafa
## Min. : 1.000 Min. : 1.000 Min. : 1.000 Min. : 13
## 1st Qu.: 1.000 1st Qu.: 3.000 1st Qu.: 3.000 1st Qu.: 14
## Median : 2.000 Median : 4.000 Median : 3.000 Median : 678
## Mean : 3.471 Mean : 4.795 Mean : 3.502 Mean : 1142
## 3rd Qu.: 2.000 3rd Qu.: 5.000 3rd Qu.: 4.000 3rd Qu.: 1500
## Max. :997.000 Max. :997.000 Max. :997.000 Max. :32000
## NA's :3 NA's :63
## rendarange ocup freq_esc peso
## Min. : 1.000 Min. : 210 Min. :1.000 Min. : 1986
## 1st Qu.: 2.000 1st Qu.:5120 1st Qu.:1.000 1st Qu.:13718
## Median : 3.000 Median :5414 Median :1.000 Median :16010
## Mean : 4.188 Mean :6310 Mean :1.001 Mean :15614
## 3rd Qu.: 5.000 3rd Qu.:8322 3rd Qu.:1.000 3rd Qu.:17271
## Max. :15.000 Max. :9999 Max. :2.000 Max. :35224
## NA's :63 NA's :1571
## peso_pond se_trab empregados estuda_atualmente
## Min. :0.1272 Min. : 1.000 Min. :0.0000 Min. : 1.000
## 1st Qu.:0.8785 1st Qu.: 1.000 1st Qu.:0.0000 1st Qu.: 1.000
## Median :1.0254 Median : 2.000 Median :1.0000 Median : 2.000
## Mean :1.0000 Mean : 3.868 Mean :0.5222 Mean : 2.831
## 3rd Qu.:1.1061 3rd Qu.: 3.000 3rd Qu.:1.0000 3rd Qu.: 3.000
## Max. :2.2559 Max. :997.000 Max. :1.0000 Max. :997.000
## NA's :3
head(banco, n=10) # Mostra as 10 primeiras observaçoes da base de dados
## regiao sexo idade_quinquenal raca_cor educ_mae ocup_mae educ_pai ocup_pai
## 1 5 1 1 2 3 4110 2 8211
## 2 5 1 2 3 2 9994 2 5249
## 3 5 2 1 1 3 9994 3 3321
## 4 5 2 2 1 3 2359 2 9621
## 5 5 1 2 2 1 9111 1 1221
## 6 5 1 3 3 2 5312 1 8332
## 7 5 2 3 3 1 9112 2 8189
## 8 5 2 1 3 2 5244 2 3321
## 9 5 2 2 1 2 4120 3 5249
## 10 5 1 2 1 2 5249 3 5223
## educ pessoas classesocial rendafa rendarange ocup freq_esc peso
## 1 2 6 4 14 14 NA 1 11339.53
## 2 4 6 4 2800 5 NA 1 17322.46
## 3 4 5 3 11000 9 NA 1 15395.76
## 4 4 4 3 4000 6 4416 1 17925.54
## 5 1 1 3 NA NA 7112 1 15613.98
## 6 1 2 2 2100 4 4321 1 18320.97
## 7 2 4 3 1700 3 5246 1 19108.17
## 8 2 4 4 14 6 NA 1 11016.39
## 9 4 4 4 14 3 3343 1 17925.54
## 10 2 1 3 NA NA 3422 1 15613.98
## peso_pond se_trab empregados estuda_atualmente
## 1 0.7262176 4 0 1
## 2 1.1093831 2 0 1
## 3 0.9859913 2 0 1
## 4 1.1480057 1 1 1
## 5 0.9999664 1 1 3
## 6 1.1733308 1 1 3
## 7 1.2237452 1 1 2
## 8 0.7055231 4 0 1
## 9 1.1480057 1 1 1
## 10 0.9999664 1 1 2
str(banco) # Mostra a estrutura da base de dados
## 'data.frame': 3288 obs. of 20 variables:
## $ regiao : int 5 5 5 5 5 5 5 5 5 5 ...
## $ sexo : int 1 1 2 2 1 1 2 2 2 1 ...
## $ idade_quinquenal : int 1 2 1 2 2 3 3 1 2 2 ...
## $ raca_cor : int 2 3 1 1 2 3 3 3 1 1 ...
## $ educ_mae : int 3 2 3 3 1 2 1 2 2 2 ...
## $ ocup_mae : int 4110 9994 9994 2359 9111 5312 9112 5244 4120 5249 ...
## $ educ_pai : int 2 2 3 2 1 1 2 2 3 3 ...
## $ ocup_pai : int 8211 5249 3321 9621 1221 8332 8189 3321 5249 5223 ...
## $ educ : int 2 4 4 4 1 1 2 2 4 2 ...
## $ pessoas : int 6 6 5 4 1 2 4 4 4 1 ...
## $ classesocial : int 4 4 3 3 3 2 3 4 4 3 ...
## $ rendafa : int 14 2800 11000 4000 NA 2100 1700 14 14 NA ...
## $ rendarange : int 14 5 9 6 NA 4 3 6 3 NA ...
## $ ocup : int NA NA NA 4416 7112 4321 5246 NA 3343 3422 ...
## $ freq_esc : int 1 1 1 1 1 1 1 1 1 1 ...
## $ peso : num 11340 17322 15396 17926 15614 ...
## $ peso_pond : num 0.726 1.109 0.986 1.148 1 ...
## $ se_trab : int 4 2 2 1 1 1 1 4 1 1 ...
## $ empregados : int 0 0 0 1 1 1 1 0 1 1 ...
## $ estuda_atualmente: int 1 1 1 1 3 3 2 1 1 2 ...
dim(banco) # As dimensoes do dataset: linhas e colunas, respectivamente
## [1] 3288 20
names(banco) # Para ver os nomes das variaveis
## [1] "regiao" "sexo" "idade_quinquenal"
## [4] "raca_cor" "educ_mae" "ocup_mae"
## [7] "educ_pai" "ocup_pai" "educ"
## [10] "pessoas" "classesocial" "rendafa"
## [13] "rendarange" "ocup" "freq_esc"
## [16] "peso" "peso_pond" "se_trab"
## [19] "empregados" "estuda_atualmente"
Lembrando como os nomes estavam originalmente no banco:
banco <- select(dados,regiao=region, sexo=sex, idade_quinquenal=age_group, raca_cor=color_race, educ_mae=mother_edu_ens, ocup_mae=mother_occ, educ_pai=father_edu_ens, ocup_pai=father_occ, educ=level_study, pessoas=pv1, rendafa, ocup= code_occ_main, freq_esc= ever_attend, peso=weight, peso_pond=aweight, se_trab= c11_new, empregados=employed, estuda_atualmente=currently_attend)
Alternativamente ao que vimos até agora, podemos usar a função skim, do pacote skimr.
library(skimr)
skim(banco)
| Name | banco |
| Number of rows | 3288 |
| Number of columns | 20 |
| _______________________ | |
| Column type frequency: | |
| numeric | 20 |
| ________________________ | |
| Group variables | None |
Variable type: numeric
| skim_variable | n_missing | complete_rate | mean | sd | p0 | p25 | p50 | p75 | p100 | hist |
|---|---|---|---|---|---|---|---|---|---|---|
| regiao | 0 | 1.00 | 3.69 | 1.31 | 1.00 | 3.00 | 4.00 | 5.00 | 5.00 | ▂▂▆▃▇ |
| sexo | 0 | 1.00 | 1.50 | 0.50 | 1.00 | 1.00 | 2.00 | 2.00 | 2.00 | ▇▁▁▁▇ |
| idade_quinquenal | 0 | 1.00 | 1.92 | 0.83 | 1.00 | 1.00 | 2.00 | 3.00 | 3.00 | ▇▁▆▁▆ |
| raca_cor | 0 | 1.00 | 9.65 | 84.69 | 1.00 | 1.00 | 3.00 | 3.00 | 997.00 | ▇▁▁▁▁ |
| educ_mae | 0 | 1.00 | 6.91 | 21.02 | 1.00 | 1.00 | 1.00 | 2.00 | 99.00 | ▇▁▁▁▁ |
| ocup_mae | 0 | 1.00 | 7950.61 | 2629.43 | 1111.00 | 5249.00 | 9121.00 | 9994.00 | 9998.00 | ▁▁▂▁▇ |
| educ_pai | 0 | 1.00 | 18.62 | 36.26 | 1.00 | 1.00 | 2.00 | 9.00 | 99.00 | ▇▁▁▁▂ |
| ocup_pai | 0 | 1.00 | 7208.84 | 2514.92 | 110.00 | 5414.00 | 7411.00 | 9211.00 | 9998.00 | ▁▁▂▅▇ |
| educ | 3 | 1.00 | 3.47 | 38.81 | 1.00 | 1.00 | 2.00 | 2.00 | 997.00 | ▇▁▁▁▁ |
| pessoas | 0 | 1.00 | 4.80 | 24.54 | 1.00 | 3.00 | 4.00 | 5.00 | 997.00 | ▇▁▁▁▁ |
| classesocial | 0 | 1.00 | 3.50 | 17.35 | 1.00 | 3.00 | 3.00 | 4.00 | 997.00 | ▇▁▁▁▁ |
| rendafa | 63 | 0.98 | 1141.70 | 1703.69 | 13.00 | 14.00 | 678.00 | 1500.00 | 32000.00 | ▇▁▁▁▁ |
| rendarange | 63 | 0.98 | 4.19 | 3.74 | 1.00 | 2.00 | 3.00 | 5.00 | 15.00 | ▇▃▁▁▁ |
| ocup | 1571 | 0.52 | 6309.57 | 2273.48 | 210.00 | 5120.00 | 5414.00 | 8322.00 | 9999.00 | ▁▂▇▅▆ |
| freq_esc | 0 | 1.00 | 1.00 | 0.03 | 1.00 | 1.00 | 1.00 | 1.00 | 2.00 | ▇▁▁▁▁ |
| peso | 0 | 1.00 | 15614.50 | 2858.22 | 1985.50 | 13717.83 | 16010.40 | 17270.85 | 35224.00 | ▁▅▇▁▁ |
| peso_pond | 0 | 1.00 | 1.00 | 0.18 | 0.13 | 0.88 | 1.03 | 1.11 | 2.26 | ▁▅▇▁▁ |
| se_trab | 0 | 1.00 | 3.87 | 42.49 | 1.00 | 1.00 | 2.00 | 3.00 | 997.00 | ▇▁▁▁▁ |
| empregados | 0 | 1.00 | 0.52 | 0.50 | 0.00 | 0.00 | 1.00 | 1.00 | 1.00 | ▇▁▁▁▇ |
| estuda_atualmente | 3 | 1.00 | 2.83 | 30.07 | 1.00 | 1.00 | 2.00 | 3.00 | 997.00 | ▇▁▁▁▁ |
O que retirar das primeiras impressões?
As categorias das das variáveis estão codificadas (tipo numérico); portanto, elas precisam ser rotuladas com apoio do dicionário de dados (documentação do banco).
“pessoas” é uma variável numérica mas temos um valor muito discrepante (997); isso também pode ser um código.
“educ”, “rendafa”, “ocup” e “estuda_atualmente” tem valores faltantes (NAs ou missing data).
Além disso, já vamos checar valores duplicados. Em condições ideais, o banco deveria ter uma variável única, identificadora. Acabamos não acrescentando uma variável desse tipo no banco, mas vou deixar o procedimento aqui de qualquer forma.
sum(duplicated(banco))
## [1] 0
Pare remover valores duplicados: banco <- banco[!duplicated(banco),] Lembrando a lógica do R: [linha, coluna]; o ponto de exclamação significa grosseiramente “não isto” (ou “todo o resto menos isto”). Então fica algo como: o banco é igual a banco sem os duplicados do banco.
Vamos dar continuidade rotulando as variáveis categóricas para em seguida tratar as demais.
banco <- banco %>%
mutate(educ = case_when(
(estuda_atualmente == 1 & educ == 1) ~ "Fundamental incompleto ou menos",
(estuda_atualmente == 2 & educ == 1) ~ "Fundamental completo até médio incompleto",
(estuda_atualmente == 3 & educ == 1) ~ "Fundamental incompleto ou menos",
(estuda_atualmente == 1 & educ == 2) ~ "Fundamental completo até médio incompleto",
(estuda_atualmente == 2 & educ == 2) ~ "Médio completo até superior incompleto",
(estuda_atualmente == 3 & educ == 2) ~ "Fundamental completo até médio incompleto",
(estuda_atualmente == 1 & educ == 3) ~ "Médio completo até superior incompleto",
(estuda_atualmente == 2 & educ == 3) ~ "Superior completo ou mais",
(estuda_atualmente == 3 & educ == 3) ~ "Médio completo até superior incompleto",
(estuda_atualmente == 1 & educ == 4) ~ "Médio completo até superior incompleto",
(estuda_atualmente == 2 & educ == 4) ~ "Superior completo ou mais",
(estuda_atualmente == 3 & educ == 4) ~ "Médio completo até superior incompleto",
(estuda_atualmente == 1 & educ == 5) ~ "Superior completo ou mais",
(estuda_atualmente == 2 & educ == 5) ~ "Superior completo ou mais",
(estuda_atualmente == 3 & educ == 5) ~ "Superior completo ou mais"),
regiao = case_when(
(regiao == 1) ~"Norte",
(regiao == 2) ~ "Centro-Oeste",
(regiao == 3) ~"Nordeste",
(regiao == 4) ~ "Sul",
(regiao == 5) ~ "Sudeste"),
sexo = case_when(
(sexo == 1) ~ "Masculino",
(sexo == 2) ~ "Feminino"),
idade_quinquenal = case_when(
(idade_quinquenal == 1) ~ "15 a 19 anos",
(idade_quinquenal == 2) ~"20 a 24 anos",
(idade_quinquenal == 3) ~"25 a 29 anos"),
raca_cor = case_when(
(raca_cor == 1) ~ "Branca",
(raca_cor == 2) ~ "Negra",
(raca_cor == 3) ~ "Negra",
(raca_cor == 4) ~ "Outros",
(raca_cor == 5) ~ "Outros",
(raca_cor == 6) ~ "Outros",
(raca_cor == 7) ~ "Outros",
(raca_cor == 8) ~ "Negra",
(raca_cor == 9) ~ "Outros",
(raca_cor == 10) ~"Outros",
(raca_cor == 11) ~"Outros",
(raca_cor == 997) ~"Outros"),
educ_mae = case_when(
(educ_mae == 1) ~ "Ensino Fundamental ou menos",
(educ_mae == 2) ~ "Ensino Médio ou técnico",
(educ_mae == 3) ~ "Ensino Superior ou mais",
(educ_mae == 4) ~ "Ensino Superior ou mais",
(educ_mae == 9) ~ "Ensino Fundamental ou menos",
(educ_mae == 99) ~ "Não sabe"),
educ_pai = case_when(
(educ_pai == 1)~ "Ensino Fundamental ou menos",
(educ_pai == 2)~ "Ensino Médio ou técnico",
(educ_pai == 3)~ "Ensino Superior ou mais",
(educ_pai == 4)~ "Ensino Superior ou mais",
(educ_pai == 9)~ "Ensino Fundamental ou menos",
(educ_pai == 99)~ "Não sabe"),
ocup=case_when(
between(ocup, 1111, 3522) ~ "Classe 1",
between(ocup, 4110, 5419) ~ "Classe 2",
between(ocup, 6111, 6225) ~ "Classe 3",
between(ocup, 7111, 8350) ~ "Classe 2",
between(ocup, 9111, 9996) ~ "Classe 3",
between(ocup, 9997, 9999) ~ "Outros"),
ocup_mae = case_when (between(ocup_mae, 1111, 3522) ~ "Classe 1",
between(ocup_mae, 4110, 5419) ~ "Classe 2",
between(ocup_mae, 6111, 6225) ~ "Classe 3",
between(ocup_mae, 7111, 8350) ~ "Classe 2",
between(ocup_mae, 9111, 9996) ~ "Classe 3",
between(ocup_mae, 9997, 9999) ~ "Outros"),
ocup_pai = case_when (between(ocup_pai, 1111, 3522) ~ "Classe 1",
between(ocup_pai, 4110, 5419) ~ "Classe 2",
between(ocup_pai, 6111, 6225) ~ "Classe 3",
between(ocup_pai, 7111, 8350) ~ "Classe 2",
between(ocup_pai, 9111, 9996) ~ "Classe 3",
between(ocup_pai, 9997, 9999) ~ "Outros"),
empregados = case_when(
empregados == 0 ~ "Não",
empregados == 1 ~ "Sim"),
classesocial = case_when(
classesocial == 1 ~ "Muito pobre",
classesocial == 2 ~ "Pobre",
classesocial == 3 ~ "Média baixa",
classesocial == 4 ~ "Média",
classesocial == 5 ~ "Média alta",
classesocial == 6 ~ "Alta",
classesocial == 9 ~ "NS/NR",
classesocial == 997 ~ "NS/NR"),
pessoas = ifelse(pessoas == 997, NA, pessoas))
Continuem com estuda_atualmente e setrab.
Tínhamos quatro colunas com valores faltantes: “ocup”, “rendafa”, “ocup_pai” e “rendafa”. Com o summary não conseguimos ver todos os NAs após a aplicação dos rótulos. Por esse motivo precisamos verificar de forma mais direta.
Outra forma de checar NAs é fazer as somas de NAs para todas as variáveis.
banco %>%
select(everything()) %>% # substitua em select as vars de escolha, segundo seu objetivo
summarise_all(funs(sum(is.na(.))))
## Warning: `funs()` was deprecated in dplyr 0.8.0.
## ℹ Please use a list of either functions or lambdas:
##
## # Simple named list: list(mean = mean, median = median)
##
## # Auto named with `tibble::lst()`: tibble::lst(mean, median)
##
## # Using lambdas list(~ mean(., trim = .2), ~ median(., na.rm = TRUE))
## regiao sexo idade_quinquenal raca_cor educ_mae ocup_mae educ_pai ocup_pai
## 1 0 0 0 0 0 0 0 45
## educ pessoas classesocial rendafa rendarange ocup freq_esc peso peso_pond
## 1 11 2 0 63 63 1575 0 0 0
## se_trab empregados estuda_atualmente
## 1 0 0 3
Com a soma de NAs, outras variáveis com valores faltantes aparecem. No caso, “educ_pai” e “pessoas”. Uma forma mais rápida de checar uma coluna individual é com o R base:
sum(is.na(banco$rendafa))
## [1] 63
Importante prestarmos atenção no montante de NAs; se forem poucos, podemos só excluir esses casos. Contudo, caso os dados faltantes ultrapasse 5% do total de casos para uma determinada categoria, algo deve ser feito e estratégias mais robustas devem ser adotadas. Há ainda outros critérios válidos e outros limiares críticos possíveis, tudo depende dos seus objetivos de pesquisa - inclusive, uma variável com muitos NAs pode ser somente descartada se isso fizer sentido no seu caso. O mais importante é investigar o que pode estar acontecendo se a decisão for manter a variável afetada.
Vamos começar com ocupação. No dicionário de dados, vemos que essa é uma resposta válida apenas para quem está empregado. Portanto, podemos substituir os NAs por “não se aplica”, pois a resposta não faz sentido para quem declarou não estar ocupado no momento, então não necessariamente é um dado perdido. Essa é uma solução específica a este banco e envolve conhecimento do dicionário de dados. A documentação da pesquisa é muitíssimo utilizada em todas as etapas da pesquisa.
banco <- banco %>% replace_na(list(ocup = "não se aplica")) #substituindo NAs por "não se aplica)
table(banco$ocup)
##
## Classe 1 Classe 2 Classe 3 não se aplica Outros
## 213 1098 398 1575 4
Poderíamos fazer o mesmo com ocupação do pai? O que vocês acham? (agregar à categoria ‘outros’, por exemplo).
Agora vamos para rendafa, quem tem 63 NAs de partida. A variável renda tende a ser complicada e com muitos NAs em diversas pesquisas. Vamos checar o dicionario de dados. Valores variam de R$100 a R$32.000.
13 - nenhuma renda; 14 - Não sabe; 15 - Recusa.
Não podemos usar o case_when como nos casos acima sob o risco de transformar a variável contínua em categórica. Vamos usar a função ifelse. O argumento dela é como segue:
Se a variável assume x valor, atribua isso (senão), atribua aquilo.
rendafa = ifelse(rendafa == 13, 0, ifelse(rendafa == 14, NA, ifelse(rendada == 15, NA, rendafa)))
Rendafa inicialmente tinha 63 NAS. Vamos checar de novo, dessa vez para todo o banco. (rodar o mesmo código de soma de NAs acima).
Depois da transformação ainda temos 1335 valores faltantes de renda. Vamos investigar essa variável primeiro. Os valores 13, 14 e 15, como vimos, são códigos. Então apesar dessa ser uma variável quantitativa, vamos fazer uma tabela de frequência e ver se os valores faltantes estão concentrados nesses primeiros números. O padrão das tabelas e apresentacao crescente, dos valores mais baixos aos mais altos.
A categoria 13 (Sem renda) tem 27 casos; a categoria 14 (Não sabe), 1139; a categoria 15 (NR), 133. Encontramos nosso problema. A categoria “não sabe” corresponde a um terço do banco. O banco tem duas variáveis que identificam renda e uma que identifica classe social (esta última de auto-declaração). A categoria de renda agrupada sofre de não respostas da mesma forma que a renda familiar em valores contínuos. Algumas soluções caberiam aqui: excluir ou substituir os valores faltantes.
A estratégia de substituir também contém diversas alternativas: substituição pelo valor médio, pelo valor médio dos vizinhos, por modelagem, entre outras. Para efeitos do exercício, contudo, vamos aproveitar a variável de classe social do banco. Podemos converter “muito pobre”, “pobre” etc. em valores de salário mínimo do ano de referência, 2013.
table(banco$classesocial)
##
## Alta Média Média alta Média baixa Muito pobre NS/NR
## 4 1067 107 1463 32 7
## Pobre
## 608
Vamos substituir os valores usando como base o salário mínimo do ano.
banco <- banco %>%
mutate(rendafa =
ifelse(rendafa == 13, 0,
ifelse(rendafa == 14 & classesocial == "Muito pobre", 678,
ifelse(rendafa == 14 & classesocial == "Pobre", 2034,
ifelse(rendafa == 14 & classesocial == "Média baixa", 3729,
ifelse(rendafa == 14 & classesocial == "Média", 5763,
ifelse(rendafa == 14 & classesocial == "Média alta", 10170,
ifelse(rendafa == 14 & classesocial == "Alta", 13561, rendafa))))))))
Agora vamos resolver os casos que não cumprem nenhum desses requisitos:
banco <- banco %>%
mutate(rendafa =
ifelse(rendafa == 14, NA,
ifelse(rendafa == 15, NA, rendafa)))
Agora podemos computar uma variável derivada com mais confiança. Uma delas é a renda per capita, por ela ter valores menos extremos e por ser uma medida mais comparável.
banco <- banco %>%
mutate(rendapercap = (rendafa/pessoas))
Mais uma checagem de NAs.
banco %>%
select(everything()) %>%
summarise_all(funs(sum(is.na(.))))
## regiao sexo idade_quinquenal raca_cor educ_mae ocup_mae educ_pai ocup_pai
## 1 0 0 0 0 0 0 0 45
## educ pessoas classesocial rendafa rendarange ocup freq_esc peso peso_pond
## 1 11 2 0 201 63 0 0 0 0
## se_trab empregados estuda_atualmente rendapercap
## 1 0 0 3 202
Podemos remover os NAs (essa é uma decisão arbitrária que nas pesquisas deve ser muito bem justificada). Mas antes vamos remover uma coluna que não será tratada.
banco <- select(banco, -rendarange)
head(banco, n = 3)
## regiao sexo idade_quinquenal raca_cor educ_mae ocup_mae
## 1 Sudeste Masculino 15 a 19 anos Negra Ensino Superior ou mais Classe 2
## 2 Sudeste Masculino 20 a 24 anos Negra Ensino Médio ou técnico Classe 3
## 3 Sudeste Feminino 15 a 19 anos Branca Ensino Superior ou mais Classe 3
## educ_pai ocup_pai educ
## 1 Ensino Médio ou técnico Classe 2 Fundamental completo até médio incompleto
## 2 Ensino Médio ou técnico Classe 2 Médio completo até superior incompleto
## 3 Ensino Superior ou mais Classe 1 Médio completo até superior incompleto
## pessoas classesocial rendafa ocup freq_esc peso peso_pond
## 1 6 Média 5763 não se aplica 1 11339.53 0.7262176
## 2 6 Média 2800 não se aplica 1 17322.46 1.1093831
## 3 5 Média baixa 11000 não se aplica 1 15395.76 0.9859913
## se_trab empregados estuda_atualmente rendapercap
## 1 4 Não 1 960.5000
## 2 2 Não 1 466.6667
## 3 2 Não 1 2200.0000
Remoção dos NAs e novo summary.
banco <- banco %>% drop_na()
skim(banco)
| Name | banco |
| Number of rows | 3036 |
| Number of columns | 20 |
| _______________________ | |
| Column type frequency: | |
| character | 12 |
| numeric | 8 |
| ________________________ | |
| Group variables | None |
Variable type: character
| skim_variable | n_missing | complete_rate | min | max | empty | n_unique | whitespace |
|---|---|---|---|---|---|---|---|
| regiao | 0 | 1 | 3 | 12 | 0 | 5 | 0 |
| sexo | 0 | 1 | 8 | 9 | 0 | 2 | 0 |
| idade_quinquenal | 0 | 1 | 12 | 12 | 0 | 3 | 0 |
| raca_cor | 0 | 1 | 5 | 6 | 0 | 3 | 0 |
| educ_mae | 0 | 1 | 8 | 27 | 0 | 4 | 0 |
| ocup_mae | 0 | 1 | 6 | 8 | 0 | 4 | 0 |
| educ_pai | 0 | 1 | 8 | 27 | 0 | 4 | 0 |
| ocup_pai | 0 | 1 | 6 | 8 | 0 | 4 | 0 |
| educ | 0 | 1 | 25 | 41 | 0 | 4 | 0 |
| classesocial | 0 | 1 | 4 | 11 | 0 | 7 | 0 |
| ocup | 0 | 1 | 6 | 13 | 0 | 5 | 0 |
| empregados | 0 | 1 | 3 | 3 | 0 | 2 | 0 |
Variable type: numeric
| skim_variable | n_missing | complete_rate | mean | sd | p0 | p25 | p50 | p75 | p100 | hist |
|---|---|---|---|---|---|---|---|---|---|---|
| pessoas | 0 | 1 | 4.26 | 1.72 | 2.00 | 3.00 | 4.00 | 5.00 | 14.00 | ▇▃▁▁▁ |
| rendafa | 0 | 1 | 2840.61 | 2238.75 | 0.00 | 1200.00 | 2034.00 | 3729.00 | 32000.00 | ▇▁▁▁▁ |
| freq_esc | 0 | 1 | 1.00 | 0.00 | 1.00 | 1.00 | 1.00 | 1.00 | 1.00 | ▁▁▇▁▁ |
| peso | 0 | 1 | 15588.22 | 2883.22 | 1985.50 | 13610.07 | 16004.67 | 17240.11 | 35224.00 | ▁▅▇▁▁ |
| peso_pond | 0 | 1 | 1.00 | 0.18 | 0.13 | 0.87 | 1.02 | 1.10 | 2.26 | ▁▅▇▁▁ |
| se_trab | 0 | 1 | 3.70 | 40.37 | 1.00 | 1.00 | 2.00 | 3.00 | 997.00 | ▇▁▁▁▁ |
| estuda_atualmente | 0 | 1 | 1.92 | 0.84 | 1.00 | 1.00 | 2.00 | 3.00 | 3.00 | ▇▁▆▁▆ |
| rendapercap | 0 | 1 | 759.86 | 710.45 | 0.00 | 280.00 | 541.20 | 1017.00 | 10666.67 | ▇▁▁▁▁ |
A forma mais simples e frutífera de iniciar a análise é através das tabelas de frequência. Erros de rotulação podem ser identificados, e demais inconsistências que passaram despecebidas inicialmente podem aparecer. Vamos usar a biblioteca formattable, que é bem integrada com o universo do tidyverse. Mas vocês podem optar por outras bibliotecas também.
library(formattable)
regtab <- banco %>%
group_by(regiao) %>%
summarise(cnt = n()) %>%
mutate(perc = formattable::percent(cnt / sum(cnt))) %>%
arrange(desc(perc))
print(regtab)
## # A tibble: 5 × 3
## regiao cnt perc
## <chr> <int> <formttbl>
## 1 Sudeste 1229 40.48%
## 2 Nordeste 903 29.74%
## 3 Sul 416 13.70%
## 4 Norte 283 9.32%
## 5 Centro-Oeste 205 6.75%
sexotab <- banco %>%
group_by(sexo) %>%
summarise(cnt = n()) %>%
mutate(perc = formattable::percent(cnt / sum(cnt))) %>%
arrange(desc(perc))
print(sexotab)
## # A tibble: 2 × 3
## sexo cnt perc
## <chr> <int> <formttbl>
## 1 Feminino 1546 50.92%
## 2 Masculino 1490 49.08%
Continuem com mais algum exemplo.
Em bancos com muitas colunas, uma demanda pode ser a automatização da tarefa de gerar tabelas de frequência simples. O pacote janitor tem uma boa solução para isso (janitor é uma biblioteca de limepza e tratamento de dados).
library(janitor)
Vamos usar a função de base tabyl do janitor. Elar etorna o n (frequência ou count) e percentual. Se há dados faltantes (NAs), ela calcula o percentual total e o percentual válido.
tabyl(banco$sexo)
## banco$sexo n percent
## Feminino 1546 0.5092227
## Masculino 1490 0.4907773
Para a automatização vamos combinar uma função do R com a função do janitor. Da forma que está, a função pode ser reproduzida para demais bancos de dados. Apenas em “map” e no parâmetro de data frame é que substituímos com nossos próprios valores.
# A função
tabyl_n <- function(df, x) { #df de dataframe
df %>%
tabyl({{x}}) %>%
adorn_pct_formatting(digits = 1) # converte freqs para props
}
# Aplicação da função; map "mapeia" as colunas para os quais a função será aplicada
map(c("regiao", "sexo", "idade_quinquenal", "raca_cor", "educ_mae",
"ocup_mae", "educ_pai", "ocup_pai", "classesocial", "ocup",
"educ", "empregados"), ~tabyl_n(banco, .x))
## Warning: Using an external vector in selections was deprecated in tidyselect 1.1.0.
## ℹ Please use `all_of()` or `any_of()` instead.
## # Was:
## data %>% select(.x)
##
## # Now:
## data %>% select(all_of(.x))
##
## See <https://tidyselect.r-lib.org/reference/faq-external-vector.html>.
## [[1]]
## regiao n percent
## Centro-Oeste 205 6.8%
## Nordeste 903 29.7%
## Norte 283 9.3%
## Sudeste 1229 40.5%
## Sul 416 13.7%
##
## [[2]]
## sexo n percent
## Feminino 1546 50.9%
## Masculino 1490 49.1%
##
## [[3]]
## idade_quinquenal n percent
## 15 a 19 anos 1211 39.9%
## 20 a 24 anos 905 29.8%
## 25 a 29 anos 920 30.3%
##
## [[4]]
## raca_cor n percent
## Branca 1022 33.7%
## Negra 1789 58.9%
## Outros 225 7.4%
##
## [[5]]
## educ_mae n percent
## Ensino Fundamental ou menos 1991 65.6%
## Ensino Médio ou técnico 685 22.6%
## Ensino Superior ou mais 211 6.9%
## Não sabe 149 4.9%
##
## [[6]]
## ocup_mae n percent
## Classe 1 327 10.8%
## Classe 2 604 19.9%
## Classe 3 2038 67.1%
## Outros 67 2.2%
##
## [[7]]
## educ_pai n percent
## Ensino Fundamental ou menos 1762 58.0%
## Ensino Médio ou técnico 593 19.5%
## Ensino Superior ou mais 172 5.7%
## Não sabe 509 16.8%
##
## [[8]]
## ocup_pai n percent
## Classe 1 336 11.1%
## Classe 2 1452 47.8%
## Classe 3 886 29.2%
## Outros 362 11.9%
##
## [[9]]
## classesocial n percent
## Alta 3 0.1%
## Média 975 32.1%
## Média alta 92 3.0%
## Média baixa 1368 45.1%
## Muito pobre 30 1.0%
## NS/NR 1 0.0%
## Pobre 567 18.7%
##
## [[10]]
## ocup n percent
## Classe 1 182 6.0%
## Classe 2 1006 33.1%
## Classe 3 371 12.2%
## não se aplica 1474 48.6%
## Outros 3 0.1%
##
## [[11]]
## educ n percent
## Fundamental completo até médio incompleto 1067 35.1%
## Fundamental incompleto ou menos 876 28.9%
## Médio completo até superior incompleto 996 32.8%
## Superior completo ou mais 97 3.2%
##
## [[12]]
## empregados n percent
## Não 1471 48.5%
## Sim 1565 51.5%
O ggplot2, gramática dos gráficos
“ggplot2 is designed to work in a layered fashion, starting with a layer showing the raw data then adding layers of annotations and statistical summaries. It allows you to produce graphics using the same structured thinking that you use to design an analysis, reducing the distance between a plot in your head and one on the page. […].
In ggplot2, the expressions used to create a new graphic are composed of higher-level elements like representations of the raw data and statistical transformations, and can easily be combined with new datasets and other plots. […].
Wilkinson (2005) created the grammar of graphics to describe the deep features that underlie all statistical graphics. The grammar of graphics is an answer to a question: what is a statistical graphic? The layered grammar of graphics (Wickham, 2009) builds on Wilkinson’s grammar, focussing on the primacy of layers and adapting it for embedding within R. In brief, the grammar tells us that a statistical graphic is a mapping from data to aesthetic attributes (colour, shape, size) of geometric objects (points, lines, bars). The plot may also contain statistical transformations of the data and is drawn on a specific coordinate system. Faceting can be used to generate the same plot for different subsets of the dataset. It is the combination of these independent components that make up a graphic.” (Wickham, 2009)
Tradução livre
“O ggplot2 foi contruído para operar em camadas, começando com uma camada que contém os dados brutos seguido pela adição de camadas com anotações e sínteses estatíticas. Isso permite que você produza gráficos usando o mesmo raciocínio empregado no desenho da análise, o que reduz a distância de um gráfico na sua cabeça e aquele na página (tradução suuuper livre) […].
No ggplot2, as expressões usadas para criar um novo gráfico são compostas de elementos de nível mais elevado como representações dos dados brutos e transformações estatíticas, que podem ser facilmente combinados com novos datasets e outros gráficos […].
Wilkinson (2005) criou a gramática dos gráficos para descrever os atributos mais profundos subjacentes a todos os gráficos estatísticos. A gramática dos gráficos é uma resposta à pergunta: o que é um gráfico estatístico? A gramática dos gráficos em camadas (Wickham, 2009) se baseia na gramática de Wilkinson, com foco na primazia das camadas e adapatação à interface R. Resumidamente, a gramática nos diz que um gráfico estatístico é um mapeamento que vai dos dados aos atributos estéticos (cor, forma, tamanho) de objetos geométricos (pontos, linhas, barras). O gráfico ainda pode conter transformações estatíticas dos dados, desenhado num sistema de coordenadas específico. O faceting pode ser usado para gerar o mesmo gráfico para diferentes subsets do banco. É a combinação dessas componentes independentes que faz um gráfico.”
data - os dados que vocês quer representar (seu banco de dados)
aesthetic mappings - descreve como as variáveis no banco serão representadas. Qual estará no eixo x? Qual no eixo y? Você quer discriminar a representação segundo fatores de uma terceira variável (fill e color)? Para cada atributo estético há uma função scale específica. Isso vai ficar mais evidente mais para frente.
geoms - representa o que quero ver no gráfico: pontos, barras, linhas, polígonos etc.
stats - formar de sumarizar o os dados, como bins do histograma, contagem de frequência, média etc. É opcional mas bastante útil.
scales - mapeia valores no espaço dos dados para um espaço estético, seja em cor, tamanho ou forma. Scales pode desenhar legenda ou eixos, por exemplo.
coord - o sistema de coordenadas descreve como as coordenadas dos dados serão mapeadas no plano gráfico. Usualmente o plano cartesiano é usado, mas há alternativas (como no gráfico de pizza, por exemplo).
faceting - especifica como e se podemos partir o banco em subsets e como representá-los.
ggplot(banco, aes(x = sexo)) + geom_bar() #depois do "+" já estamos mobilizando as camadas
Construímos o restante do gráfico a partir desse primeiro bloco:
ggplot(data = banco, aes(x = var1, y = var2, color = var3)) #fill ou color são opcionais; por vezes também não precisamos do x e y de uma vez só.
A partir dessa mesma ideia de gráfico inicial vamos mudar as cores da barra e deixar as categorias em ordem decrescente. (Isso ao mesmo tempo em que salvamos o arquivo em png no código do curso).
ggplot(banco, aes(x = reorder(regiao, regiao,
function(x)-length(x)))) +
geom_bar(stat = "count", width = 0.7, fill = "#697a55", position = "dodge") +
theme_light() +
ggtitle("Regiões") +
theme(plot.title = element_text(hjust = 0.5)) +
xlab("") + ylab("Frequência")
Troquem: stat = “identity”; position = “fill”; mudem o parâmetro de width para outro número; retirem o theme(plot.title…); retirem o ggtitle; retirem o xlab e ylab. Façam as mudanças uma vez de cada, para que vocês vejam o que muda em cada caso!
Podemos colocar o número da frequência nas barras.
ggplot(banco, aes(x = reorder(classesocial, classesocial,
function(x)-length(x)))) +
geom_bar(stat = "count", width = 1, color = "black", fill = "#dba3a3") +
theme_light() +
labs(title = "Classe \n social", x = "", y = "Frequência") +
theme(plot.title = element_text(hjust = 0.5)) +
geom_text(stat='count', aes(label=..count..), vjust = -0.9, color = "black",
position = position_dodge(0.9), size=3.5) # adicionar detalhes
Retirem o parâmetro fill e deixem apenas o color. Notem que para essas mudanças de cor o argumento não está dentro de aes. Tentem trocar (colocar o argumento color = “black” dentro dos parênteses do aes acima). O que acontece?
Por vezes a representação por frequências pode não ser a mais informativa, ou pode não destacar apropriadamente diferenças entre grupos. Vamos ver duas maneiras de transformar as frequências em percentuais: diretamente no ggplot, usando argumentos do stat e com apoio do dplyr - ou seja, transformando o dado antes de plotar.
ggplot(banco, aes(x = raca_cor)) +
theme_classic() +
geom_bar(aes(y = after_stat(count / sum(count))), color="#697a55", fill="white") +
scale_y_continuous(labels = scales::percent) + #para cada aes um correspondente scale
labs(x = "", y = "Percentual")
A solução mais certeira acaba sendo calcular os percentuais de antemão usando os recursos do tidyverse, como com o dplyr. Como o ggplot2 foi construído com a mesma lógica, as duas bibliotecas conversam bem.
educmae <- banco %>%
count(educ_mae) %>%
mutate(pct = n / sum(n)) %>%
ggplot(aes(x = educ_mae, fill = educ_mae)) +
geom_col(aes(y = pct)) +
scale_y_continuous(labels = scales::percent)
(Bônus: |> essa é outra forma de escrever o pipe)
Perceberam que rodamos o código acima e nada aconteceu? Criar um objeto mais simples como base do gráfico pode ajudar a visualização quando as especificações adicionais do gráfico ficarem mais complexas. É o que vai acontecer agora que vamos adicionar mais detalhes. Vamos mudar aspectos da legenda, mudar labels e a paleta de cores.
educmae + theme_light() +
labs(x = "", y = "", fill = "Educação da mãe", caption = "Fonte: OIT, 2013.") +
scale_x_discrete(breaks = c("Ensino Fundamental ou menos","Ensino Médio ou técnico","Ensino Superior ou mais", "Não sabe"),
labels = c("E. Fundamental \n ou menos", "E. Médio \n ou técnico", "E. Superior \n ou mais", "Não \n sabe")) + #esse scale se refere ao eixo x
theme(legend.key.size = unit(0.3, 'cm'), # muda o tamanho dos quadradinhos da legenda
legend.key.height = unit(0.3, 'cm'), # muda a altura dos quadradinhos da legenda
legend.key.width = unit(0.3, 'cm'), # muda a largura dos quadradinhos da legenda
legend.title = element_text(size = 10), # muda o tamanho da fonte do título da legenda
legend.text = element_text(size = 8)) + # muda o tamanho da fonte do texto da legenda
scale_fill_brewer(palette = "Dark2") # esse scale_fill... se refere ao aes(fill=)
Dêem um print(educmae) e vejam o gráfico original, sem as especificações. As mudanças sugeridas fazem sentido para vocês?
banco %>%
ggplot(aes(x = "", fill = educ_pai)) +
geom_bar(position = "fill", width = 1) +
coord_polar(theta = "y") + #aqui já não estamos no plano cartesiano convencional
labs(title = "",
x = "",
y = "",
fill = "Educação do pai") +
theme_void() +
scale_fill_brewer(palette = "Dark2")
Substituam o theme_void() por qualquer outro e vejam o que acontece.
Vamos fazer uma transformação prévia do dado (parecido com o que fizemos acima), mas alocando para uma tabela à parte (no formato data.frame).
educpai <- banco %>%
group_by(educ_pai) %>% # Variável a ser transformada
count() %>%
ungroup() %>%
mutate(perc = `n` / sum(`n`)) %>%
arrange(perc) %>%
mutate(labels = scales::percent(perc))
print(educpai)
## # A tibble: 4 × 4
## educ_pai n perc labels
## <chr> <int> <dbl> <chr>
## 1 Ensino Superior ou mais 172 0.0567 5.7%
## 2 Não sabe 509 0.168 16.8%
## 3 Ensino Médio ou técnico 593 0.195 19.5%
## 4 Ensino Fundamental ou menos 1762 0.580 58.0%
ggplot(educpai, aes(x = "", y = perc, fill = educ_pai)) + # mudamos o banco de referência
geom_col() +
geom_text(aes(label = labels),
position = position_stack(vjust = 0.5)) +
coord_polar(theta = "y") +
labs(title = "",
x = "",
y = "",
fill = "Educação do pai") +
theme_void() +
scale_fill_brewer(palette = "Dark2")
Vamos ver os mais simples primeiro, sem muitas camadas: histograma, boxplot e densidade.
ggplot(banco, aes(x = rendapercap)) + geom_histogram()
ggplot(banco, aes(y = rendapercap)) + geom_boxplot()
ggplot(banco, aes(x = rendapercap)) + geom_density()
Recordar Estatística para Ciências Sociais é essencial! Alguém me diz o que cada linha no boxplot significa, vamos lá :D
ggplot(banco, aes(x = rendapercap)) + geom_histogram(binwidth = 1, color = "#a02a1e", fill = "#a02a1e") +
geom_vline(aes(xintercept = mean(rendapercap)),
color = "black", linetype = "dashed", size=1) +
theme_light() +
labs(x = "Renda per capita", y = "Frequência", title = "Renda per capita (e média)") +
annotate("text", x = 600, y = 125, label = "média", angle = 90) # anotação manual mesmo!
mean(banco$rendapercap) # pistas sobre onde anotar no eixo x
## [1] 759.8565
ggplot(banco, aes(y = rendapercap)) + geom_boxplot(fill = "#30407a") +
ylim(0, 6000) + # limites do eixo y, inferior e superior
theme_light() +
theme(axis.ticks.x = element_blank(), #aqui estou removendo algumas anotações do eixo x
axis.text.x = element_blank(),
plot.title = element_text(hjust = 0.5), text = element_text(family = "Times New Roman")) + #aqui estou centralizando o título e mudando a fonte, útil para a versão final dos gráficos
labs(x = "", y = "Renda per capita", title = "Distribuição da renda per capita")
## Warning: Removed 3 rows containing non-finite values (stat_boxplot).
ggplot(banco, aes(x = rendapercap)) +
geom_density(color = "black", fill = "#76949f", alpha = 0.4) + #alpha controla a "solidez" das cores; valores abaixo de 1 são mais transparentes
theme_light() +
labs(x = "Renda per capita", y = "Densidade")
ggplot(banco, aes(x = rendapercap)) +
geom_histogram(aes(y = ..density..),
colour = 1, fill = "white",
binwidth = 30) +
geom_density(lwd = 1.2,
linetype = 2,
colour = 2) +
theme_light() +
labs(x = "Renda per capita", y = "Função densidade",
title = "Distribuição da renda per capita")
O que pode estar associado à condição de estar inserido no mercado de trabalho para os jovens?
Aqui podemos fazer tabelas cruzados e mais alguns gráficos específicos para responder uma questão de pesquisa. Só vamos retomar como é a distribuição da variável em análise:
table(banco$empregados)
##
## Não Sim
## 1471 1565
Tabelas cruzadas (com outras variáveis categóricas)
Condição de emprego por sexo, usando o janitor
banco %>%
tabyl(sexo, empregados)
## sexo Não Sim
## Feminino 936 610
## Masculino 535 955
# Mais complexa
library(flextable)
banco %>%
tabyl(sexo, empregados) %>%
adorn_totals(where = "row") %>%
adorn_percentages(denominator = "col") %>%
adorn_pct_formatting() %>%
adorn_ns(position = "front") %>%
adorn_title(
row_name = "Sexo",
col_name = "Empregago",
placement = "combined") %>% # para imprimir como imagem
flextable::flextable() %>% # converte para uma imagem bonita
flextable::autofit() # formata uma linha por vez
Sexo/Empregago | Não | Sim |
Feminino | 936 (63.6%) | 610 (39.0%) |
Masculino | 535 (36.4%) | 955 (61.0%) |
Total | 1471 (100.0%) | 1565 (100.0%) |
sexo_emprego <- banco %>%
group_by(empregados) %>% # agrupapelo resultado
count(sexo) %>%
mutate(percent = scales::percent(n / sum(n))) # calculate percent - note the denominator
print(sexo_emprego)
## # A tibble: 4 × 4
## # Groups: empregados [2]
## empregados sexo n percent
## <chr> <chr> <int> <chr>
## 1 Não Feminino 936 64%
## 2 Não Masculino 535 36%
## 3 Sim Feminino 610 39%
## 4 Sim Masculino 955 61%
O formato de dados do sexo_emprego é o “long” (comprido), em vez de “wide” (largo). Pode ser mais fácil gerar gráficos dessa forma a depender do caso.
ggplot(data = sexo_emprego, aes(x = empregados, y = percent, fill = sexo)) +
geom_bar(stat = "identity", position = "dodge") #aqui já transformei o dado, então com o stat="identity" eu garanto que o stat não vai fazer mais nenhuma transformação com ele
Troquem o percent pelo n e vejam a diferença. Coloquem título no gráfico e labels nos eixos x, y e legenda (dica: para legenda, o comando pode ser “fill” ou “color” - qual é a correta nesse caso?)
Bônus: troquem o tema do gráfico.
reg <- ggplot(banco, aes(x = regiao, fill = empregados)) + geom_bar(position = "fill") +
labs(x = "", y = "Proporção", fill = "Empregado") +
theme_light() +
scale_fill_manual(values = c("#f0e8d7", "#a02a1e"))
print(reg)
reg + facet_grid(cols = vars(sexo)) +
theme(axis.text.x = element_text(angle = 45, hjust=1))
reg + facet_grid(cols = vars(raca_cor)) +
theme(axis.text.x = element_text(angle = 45, hjust=1))
idade <- banco %>%
group_by(idade_quinquenal) %>%
count(empregados) %>%
mutate(percent = scales::percent(n / sum(n)))
print(idade)
## # A tibble: 6 × 4
## # Groups: idade_quinquenal [3]
## idade_quinquenal empregados n percent
## <chr> <chr> <int> <chr>
## 1 15 a 19 anos Não 815 67%
## 2 15 a 19 anos Sim 396 33%
## 3 20 a 24 anos Não 364 40%
## 4 20 a 24 anos Sim 541 60%
## 5 25 a 29 anos Não 292 32%
## 6 25 a 29 anos Sim 628 68%
idade_plot <- ggplot(idade, aes(x = idade_quinquenal, y = percent, fill = empregados)) +
geom_bar(stat = "identity", position = "dodge") +
labs(x = "", y = "Percentual", fill = "Empregado") +
theme_light() +
scale_fill_manual(values = c("#2d3f2f", "#ccd2e6"))
print(idade_plot)
idade2 <- banco %>%
group_by(idade_quinquenal, sexo) %>%
count(empregados) %>%
mutate(percent = scales::percent(n / sum(n)))
print(idade2)
## # A tibble: 12 × 5
## # Groups: idade_quinquenal, sexo [6]
## idade_quinquenal sexo empregados n percent
## <chr> <chr> <chr> <int> <chr>
## 1 15 a 19 anos Feminino Não 465 76%
## 2 15 a 19 anos Feminino Sim 149 24%
## 3 15 a 19 anos Masculino Não 350 59%
## 4 15 a 19 anos Masculino Sim 247 41%
## 5 20 a 24 anos Feminino Não 247 55%
## 6 20 a 24 anos Feminino Sim 201 45%
## 7 20 a 24 anos Masculino Não 117 26%
## 8 20 a 24 anos Masculino Sim 340 74%
## 9 25 a 29 anos Feminino Não 224 46.3%
## 10 25 a 29 anos Feminino Sim 260 53.7%
## 11 25 a 29 anos Masculino Não 68 16%
## 12 25 a 29 anos Masculino Sim 368 84%
ggplot(idade2, aes(x = idade_quinquenal, y = percent, fill = empregados)) +
geom_bar(stat = "identity", position = "dodge") +
labs(x = "", y = "Percentual", fill = "Empregado") +
theme_light() +
scale_fill_manual(values = c("#2d3f2f", "#ccd2e6")) +
facet_grid(cols = vars(sexo)) +
theme(axis.text.x = element_text(angle = 45, hjust=1)) # ajusta o ângulo dos labels no eixo x
idade3 <- banco %>%
group_by(idade_quinquenal, raca_cor) %>% # group by outcome
count(empregados) %>% # group and count by age_cat, and then remove age_cat grouping
mutate(percent = scales::percent(n / sum(n)))
print(idade3)
## # A tibble: 18 × 5
## # Groups: idade_quinquenal, raca_cor [9]
## idade_quinquenal raca_cor empregados n percent
## <chr> <chr> <chr> <int> <chr>
## 1 15 a 19 anos Branca Não 299 70%
## 2 15 a 19 anos Branca Sim 130 30%
## 3 15 a 19 anos Negra Não 455 66%
## 4 15 a 19 anos Negra Sim 232 34%
## 5 15 a 19 anos Outros Não 61 64%
## 6 15 a 19 anos Outros Sim 34 36%
## 7 20 a 24 anos Branca Não 102 33%
## 8 20 a 24 anos Branca Sim 204 67%
## 9 20 a 24 anos Negra Não 238 44%
## 10 20 a 24 anos Negra Sim 307 56%
## 11 20 a 24 anos Outros Não 24 44%
## 12 20 a 24 anos Outros Sim 30 56%
## 13 25 a 29 anos Branca Não 85 30%
## 14 25 a 29 anos Branca Sim 202 70%
## 15 25 a 29 anos Negra Não 183 33%
## 16 25 a 29 anos Negra Sim 374 67%
## 17 25 a 29 anos Outros Não 24 32%
## 18 25 a 29 anos Outros Sim 52 68%
ggplot(idade3, aes(x = idade_quinquenal, y = percent, fill = empregados)) +
geom_bar(stat = "identity", position = "dodge") +
labs(x = "", y = "Percentual", fill = "Empregado") +
theme_light() +
scale_fill_manual(values = c("#2d3f2f", "#ccd2e6")) +
facet_grid(cols = vars(raca_cor)) +
theme(axis.text.x = element_text(angle = 45, hjust=1)) # o hjust=1 impede que a inclinação ultrapasse a área do gráfico
idade4 <- banco %>%
group_by(empregados) %>% # group by outcome
count(idade_quinquenal) %>% # group and count by age_cat, and then remove age_cat grouping
mutate(percent = scales::percent(n / sum(n)))
print(idade4)
## # A tibble: 6 × 4
## # Groups: empregados [2]
## empregados idade_quinquenal n percent
## <chr> <chr> <int> <chr>
## 1 Não 15 a 19 anos 815 55.4%
## 2 Não 20 a 24 anos 364 24.7%
## 3 Não 25 a 29 anos 292 19.9%
## 4 Sim 15 a 19 anos 396 25.3%
## 5 Sim 20 a 24 anos 541 34.6%
## 6 Sim 25 a 29 anos 628 40.1%
ggplot(idade4, aes(x = idade_quinquenal, y = percent)) +
geom_bar(stat = "identity", position = "dodge", fill = "#2d3f2f") +
labs(x = "", y = "Percentual") +
theme_light() +
facet_grid(cols = vars(empregados)) +
theme(axis.text.x = element_text(angle = 45, hjust=1))
Ficou melhor? O que vocês acham?
library(gridExtra)
# Educação
edmae <- ggplot(banco, aes(x = educ_mae, fill = empregados)) + geom_bar(position = "dodge") +
ylim(0, 1050) + #manter os dois gráficos na mesma escala
labs(x = "", y = "Frequência", fill = "Filho empregado?", title = "Educaçao da mãe") +
scale_fill_manual(values = c("#d9b268", "#6e3b2a")) +
theme_light() +
theme(axis.text.x = element_text(angle = 90, hjust = 1),
legend.position = "bottom") # posição da legenda: embaixo
print(edmae)
edpai <- ggplot(banco, aes(x = educ_pai, fill = empregados)) + geom_bar(position = "dodge") +
ylim(0, 1050) +
labs(x = "", y = "", fill = "Filho empregado?", title = "Educação do pai") +
scale_fill_manual(values = c("#d9b268", "#6e3b2a")) +
theme_light() +
theme(axis.text.x = element_text(angle = 90, hjust=1),
legend.position = "bottom")
print(edpai)
# Juntando os dois plots (educação da mãe e do pai e situação de emprego)
grid.arrange(edmae, edpai, nrow = 1) #nrow é número de linhas; também poderia usar ncol
# Ocupação
ocmae <- ggplot(banco, aes(x = ocup_mae, fill = empregados)) + geom_bar(position = "dodge") +
ylim(0, 1100) +
labs(x = "", y = "Frequência", fill = "Filho empregado?", title = "Ocupação da mãe") +
scale_fill_manual(values = c("#ccd2e6", "#2d3f2f")) +
theme_light() +
theme(axis.text.x = element_text(angle = 45, hjust = 1),
legend.position = "bottom")
print(ocmae)
ocpai <- ggplot(banco, aes(x = ocup_pai, fill = empregados)) + geom_bar(position = "dodge") +
ylim(0, 1100) +
labs(x = "", y = "", fill = "Filho empregado?", title = "Ocupação do pai") +
scale_fill_manual(values = c("#ccd2e6", "#2d3f2f")) +
theme_light() +
theme(axis.text.x = element_text(angle = 45, hjust=1),
legend.position = "bottom")
print(ocpai)
# Juntando os dois plots (ocupação dos pais e situação de emprego)
grid.arrange(ocmae, ocpai, nrow = 1)
Às vezes nos deparamos com casos em que uma das categorias de uma variável tem pouquíssimos casos em comparação com as demais, o que pode poluir a visualização do gráfico. É o que acontece com a categoria NS/NR de classe social. Podemos operar uma transformação similar com a que fizemos até agora (uso dos percentuais com o dplyr), mas apenas para o gráfico converter valores muito baixos em NAs, sem criar um novo objeto data.frame. Também podemos fazer isso sem transformar a variável no banco como um todo.
banco %>% #notem que não estou transformando o banco (banco <- banco %>% ...)
mutate(classesocial =
ifelse(classesocial == "NS/NR", NA, classesocial)) %>%
drop_na(classesocial) %>% #eliminando os NAs da transformação acima
ggplot(aes(y = factor(classesocial, levels = c("Muito pobre", "Pobre", "Média baixa", "Média",
"Média alta", "Alta")), #definição da ordem
fill = empregados)) + geom_bar(position = "dodge") +
labs(x = "Frequência", y = "", fill = "Empregados", title = "Condição de emprego por classe social") +
scale_fill_manual(values = c("dark grey", "forest green")) +
theme_light()
E assim como no caso de educação e ocupação dos pais, algumas categorias têm maior destaque pelo seu volume maior no banco. Por isso é sempre interessante também verificar a distribuição percentual.
banco %>%
tabyl(classesocial, empregados) %>%
adorn_totals(where = "row") %>%
adorn_percentages(denominator = "col") %>%
adorn_pct_formatting() %>%
adorn_ns(position = "front") %>%
adorn_title(
row_name = "Classe social",
col_name = "Empregago",
placement = "combined") %>%
flextable::flextable() %>%
flextable::autofit()
Classe social/Empregago | Não | Sim |
Alta | 3 (0.2%) | 0 (0.0%) |
Média | 442 (30.0%) | 533 (34.1%) |
Média alta | 47 (3.2%) | 45 (2.9%) |
Média baixa | 661 (44.9%) | 707 (45.2%) |
Muito pobre | 21 (1.4%) | 9 (0.6%) |
NS/NR | 0 (0.0%) | 1 (0.1%) |
Pobre | 297 (20.2%) | 270 (17.3%) |
Total | 1471 (100.0%) | 1565 (100.0%) |
A representação mais simples novamente - Renda per capita e condição de emprego:
ggplot(banco, aes(x = empregados, y = rendapercap)) + geom_boxplot()
Não parece que temos muitas diferenças entre os grupos, certo? Vamos checar os números propriamente.
statsrenda <- banco %>%
group_by(empregados) %>% #o group_by apresenta os resultados separados pelas categorias dessa variável
summarise(mean = mean(rendapercap), sd = sd(rendapercap),
median = median(rendapercap), n = n(), se = (sd / sqrt(n)))
mean = média
median = mediana
sd = desvio padrão (standard deviation)
n = número, frequência
se = erro padrão (standard error)
“Standard error of the mean (SEM) measures how far the sample mean (average) of the data is likely to be from the true population mean. The SEM is always smaller than the SD.”
O erro padrão mede o quão longe a média amostral dos dados pode estar da média verdadeira da população. O erro padrão é sempre menor do que o desvio padrão. Alguém pode me dizer por que vamos usar o erro padrão nas barras de erro do próximo gráfico?
Enfim, de fato, para os que estão empregados a renda per capita familiar é ligeiramente maior. Vamos fazer um gráfico de barras com as médias em conjunto com barras de erro informadas pelo erro padrão.
ggplot(statsrenda, aes(x = empregados, y = mean)) +
geom_bar(position = "dodge", stat="identity", fill = "#b2c6ba") +
geom_errorbar(aes(ymin = mean - se, ymax = mean + se),
width=.2, # Width of the error bars
position=position_dodge(.9)) +
labs(x = "Situação de emprego", y = "Renda familiar per capita média", title = "Rendimendo familiar per capita \n por situação de trabalho (e erro padrão)") +
theme_light() +
theme(plot.title = element_text(hjust = 0.5))
O teste qui-quadrado testa a hipótese nula de que as populações não diferam quanto às frequências de ocorrência de determinada caracterísitca. No nosso caso, a hipótese nula é a de que não há diferença de situação de emprego com relação ao sexo ou à raça/cor da população; as diferenças de frequência observadas seriam fruto apenas de erro amostral. A hipótese de pesquisa, por outro lado, afirma que as diferenças encontradas na amostra refletem diferenças populacionais reais entre os grupos, conforme captadas pelas diferenças relativas de frequência. O qui-quadrado se preocupa com as distinções entre frequências esperadas e observadas. As frequências esperadas se referem aos termos da hipótese nula, em que se espera que as frequências relativas (ou proporções) sejam as mesmas de um grupo para outro (relativamente). Somente rejeitamos a hipótese nula quando a diferença entre os valores esprados e observados é grande o bastante (ver detalhes de como o qui-quadrado é calculado em Levin, 2014).
library(descr)
# Sexo
chisq.test(table(banco$sexo, banco$empregados))
##
## Pearson's Chi-squared test with Yates' continuity correction
##
## data: table(banco$sexo, banco$empregados)
## X-squared = 183.41, df = 1, p-value < 2.2e-16
# raça/cor
chisq.test(table(banco$raca_cor, banco$empregados))
##
## Pearson's Chi-squared test
##
## data: table(banco$raca_cor, banco$empregados)
## X-squared = 0.51928, df = 2, p-value = 0.7713
x = independente; y = dependente. A ordem nas tabelas é: x, y; linha, coluna.
# Sexo
crosstab(banco$sexo, banco$empregados, expected = TRUE, chisq = TRUE, plot = FALSE)
## Cell Contents
## |-------------------------|
## | Count |
## | Expected Values |
## |-------------------------|
##
## ===================================
## banco$empregados
## banco$sexo Não Sim Total
## -----------------------------------
## Feminino 936 610 1546
## 749.1 796.9
## -----------------------------------
## Masculino 535 955 1490
## 721.9 768.1
## -----------------------------------
## Total 1471 1565 3036
## ===================================
##
## Statistics for All Table Factors
##
## Pearson's Chi-squared test
## ------------------------------------------------------------
## Chi^2 = 184.3982 d.f. = 1 p <2e-16
##
## Pearson's Chi-squared test with Yates' continuity correction
## ------------------------------------------------------------
## Chi^2 = 183.4131 d.f. = 1 p <2e-16
## Minimum expected frequency: 721.9335
# Raça/cor
crosstab(banco$raca_cor, banco$empregados, expected = TRUE, chisq = TRUE, plot = FALSE)
## Cell Contents
## |-------------------------|
## | Count |
## | Expected Values |
## |-------------------------|
##
## =======================================
## banco$empregados
## banco$raca_cor Não Sim Total
## ---------------------------------------
## Branca 486 536 1022
## 495.2 526.8
## ---------------------------------------
## Negra 876 913 1789
## 866.8 922.2
## ---------------------------------------
## Outros 109 116 225
## 109.0 116.0
## ---------------------------------------
## Total 1471 1565 3036
## =======================================
##
## Statistics for All Table Factors
##
## Pearson's Chi-squared test
## ------------------------------------------------------------
## Chi^2 = 0.5192831 d.f. = 2 p = 0.771
##
## Minimum expected frequency: 109.0168
A biblioteca janitor tem o mesmo comando crosstabs que usamos agora, mas nosso objetivo aqui é usar a função crosstabs do descr. Uma forma de resolver isso no futuro é chamando a função diretamente de um pacote específico. Então poderíamos fazer:
descr::crosstabs […]
Atenção também com o tamanho das caselas! Qui-quadrado com variável que têm muitas categorias pode gerar combinações em que o número de observações em determinadas caselas é muito baixo; isso afeta os resultados e interpretação. Evitar caselas de valor esperado com menos de 5 casos cada. Quando temos tabelas 2 x 2 (como a que usamos nos exemplos) e alguma frequência esperada é menor do que 10 mas maior do que 5, podemos usar a correção de Yates (é possível fazer com o descr mesmo).
Requisitos para o teste qui-quadrado:
O coeficiente de correlação de Pearson (que é o default do comando cor do r) oferece uma medida precisa da força e direção de associação na amostra em análise. Segue a mesma lógica do teste de hipóteses visto acima, mas a hipótese nula aqui afirma que a associação obtida entre duas variáveis é fruto apenas do acaso/erro amostral. Ou seja, a hipótese nula é a de que não há correlação entre as categorias postas à prova na população. No teste de correlação de Pearson, o coefeiciente de valor zero é o que representa a hipótese nula.
Mede a associação entre x e y, não a direção de causalidade entre x e y.
A regressão linear simples é similar à correlação na medida em que interesse ainda reside na força de associação entre duas variáveis. Mas na regressão também há interesse em conhecer a natureza dessa relação. Uma variável é definida como dependente (y) e outra como independente (x). Nesse caso, acredita-se que uma variável influencia a outra. A equação da regressão é a seguinte:
Y = a + bX + e
Ela quer dizer que os valores assumidos pelas variável dependente são a soma de três componentes:
Um valor base - ou intercepto, ou constante. É o valor esperado de Y quando X = 0. Ou seja, é o valor base porque é o que Y seria sem levar em consideração valores de X.
O termo b, que é a inclinação da reta, também chamado de coeficiente da regressão para os valores de X. Representa o montante que esperamos que Y mude (aumento ou diminuição) para cada aumento em unidade de X.
O erro ou os resíduos. É toda a variação de Y que não pode ser explicada pelo intercepto ou por bX.
Requisitos para a correlação e para a regressão linear simples
Como checar
shapiro.test(banco$rendapercap)
##
## Shapiro-Wilk normality test
##
## data: banco$rendapercap
## W = 0.76666, p-value < 2.2e-16
cor(banco$pessoas, banco$rendapercap)
## [1] -0.3275096
-0.3275096 é um coeficiente de correlação baixo e negativo. Ou seja, quando maior o número de pessoas no domicílio, menor a renda.
Agora vamos para a regressão linear simples.
regressao <- lm(formula = y(dependente) ~ x(independente), data = seubanco)
reg <- lm(formula = rendapercap ~ pessoas,
data = banco)
summary(reg)
##
## Call:
## lm(formula = rendapercap ~ pessoas, data = banco)
##
## Residuals:
## Min 1Q Median 3Q Max
## -1066.3 -458.2 -140.4 312.0 9735.7
##
## Coefficients:
## Estimate Std. Error t value Pr(>|t|)
## (Intercept) 1336.853 32.585 41.03 <2e-16 ***
## pessoas -135.292 7.086 -19.09 <2e-16 ***
## ---
## Signif. codes: 0 '***' 0.001 '**' 0.01 '*' 0.05 '.' 0.1 ' ' 1
##
## Residual standard error: 671.4 on 3034 degrees of freedom
## Multiple R-squared: 0.1073, Adjusted R-squared: 0.107
## F-statistic: 364.5 on 1 and 3034 DF, p-value: < 2.2e-16
coeff <- coefficients(reg)
intercept <- coeff[1]
slope <- coeff[2]
reg_plot <- ggplot(banco, aes(pessoas, rendapercap)) +
geom_point() +
ylim(-200, 11500) +
labs(x = "Número de pessoas no domicílio", y = "Renda familiar per capita",
title = "Relação entre renda familiar per capita \n e número de pessoas no domicílio") +
theme_light() +
theme(plot.title = element_text(hjust = 0.5))
print(reg_plot)
reg_plot + geom_abline(intercept = intercept, slope = slope, color = "#a02a1e",
linetype = "dashed", size=1.5)
Atenção nas variáveis e argumentos alocados em aes() - e em qual camada está, se na base ou nos geoms.
Atenção à classe da variável: não é possível somar ou dividir valores com variáveis categóricas; só é possível fazer isso com as suas frequências. Além disso, às vezes uma variável numérica pode ter sido importada erroneamente como categórica, ou como integer de algum outro tipo (int64). Se for esse o caso é preciso convertê-la antes. Por isso é sempre bom checar com o class ou similar. Além disso, algumas variáveis categóricas podem ser importadas como numéricas, como no nosso caso. Se você não optar pela rotulação, deve convertê-las como categóricas da mesma forma. Um exemplo:
class(banco$idade_quinquenal)
banco$idade_quinquenal <- as.character(banco$idade_quinquenal)
No dplyr:
banco <- banco %>% mutate(idade_quinquenal = as.character(idade_quinquenal))
Ou mudando várias de uma vez:
banco <- banco %>% mutate_if(is.numeric, as.character)
Ordem dos comandos no gráfico, em especial com o theme; um pode sobrescrever o outro, aí é só trocar a ordem.
Atenção com a forma de agrupamento no group_by, e qual variável escolhida melhor auxilia sua análise.
Atenção com a escolha inapropriada de gráficos para as variáveis em análise. Plotar um gráfico de barras de uma var contínua no eixo y e outra categórica no eixo x retornaria o quê? Tentem visualizar a representação gráfica teoricamente/mentalmente antes de passar para o código. Por exemplo, séries temporais e gráfico de linha fazem sentido juntos por um motivo. Esse mesmo motivo seria válido para categorias de variáveis nominais independentes entre si?
Atenção com os argumentos exigidos em cada geom. Só é possível fazer um gráfico de dispersão se temos valores para plotar tanto no eixo x como no eixo y. Esse não é um gráfico possível para análise univariada. Um histograma só pode ser feito com variáveis quantitativas, o mesmo sendo válido para o boxplot. Um conhecimento geral prévio sobre visualização gráfica é recomendável.
CERVI, Emerson U. Manual de métodos quantitativos para iniciantes em
Ciência Política –
Volume 1 / Emerson Urizzi Cervi - Curitiba: CPOP-UFPR, 2017. (1ª
edição). 256 p.
LEVIN, Jack; FOX, James A.; FORDE, David R. Elementary Statistics in Social Research. Boston: Pearson, 2014.
WICKHAM, Hadley. ggplot2. Elegant Graphics for Data Analysis. New York: Springer, 2009.
Passo a passo de construção de gráficos com o ggplot